/**
 * 
 */
package org.wolf.core.schema;

import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField;
import org.apache.lucene.spatial.DistanceUtils;
import org.apache.lucene.spatial.tier.InvalidGeoException;

/**
 * @author 何小锋
 * 
 */
public class PointField extends FieldType {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public static final int DEFAULT_DIMENSION = 2;

	/**
	 * 维度
	 */
	protected int dimension = DEFAULT_DIMENSION;

	public int getDimension() {
		if (dimension <= 0)
			dimension = DEFAULT_DIMENSION;
		return dimension;
	}

	public void setDimension(int dimension) {
		this.dimension = dimension;
	}

	@Override
	public boolean isPolyField() {
		return true;
	}

	@Override
	public Fieldable[] createFields(DocField field, Object value, float boost) {
		if (value == null)
			return new Fieldable[0];
		String val = value.toString();
		String[] point = null;
		int dimension = getDimension();
		try {
			point = DistanceUtils.parsePoint(null, val, dimension);
		} catch (InvalidGeoException e) {
			throw new IllegalArgumentException("Invalid geo " + val, e);
		}

		Fieldable[] f = new Fieldable[(field.isIndexed() ? dimension : 0)
				+ (field.isStored() ? 1 : 0)];

		if (field.isIndexed()) {
			DocField subField;
			FieldType subFieldType;
			for (int i = 0; i < dimension; i++) {
				subField = getSubField(field, i);
				subFieldType = subField.getFieldType();
				f[i] = subFieldType.createField(subField, point[i], boost);
			}
		}

		if (field.isStored()) {
			f[f.length - 1] = createField(field.getName(), val,
					Field.Store.YES, Field.Index.NO, Field.TermVector.NO,
					false, false, boost);
		}

		return f;
	}

	@Override
	public Field createField(DocField field, Object value, float boost) {
		throw new UnsupportedOperationException(
				"PointType uses multiple fields.  field=" + field.getName());
	}

	@Override
	public SortField getSortField(DocField field, boolean reverse) {
		throw new UnsupportedOperationException(
				"Sorting not suported on PointType " + field.getName());
	}

	@Override
	public Query getRangeQuery(QueryParser parser, DocField field, String min,
			String max, boolean minInclusive, boolean maxInclusive) {
		String[] p1;
		String[] p2;
		int dimension = getDimension();
		try {
			p1 = DistanceUtils.parsePoint(null, min, dimension);
			p2 = DistanceUtils.parsePoint(null, max, dimension);
		} catch (InvalidGeoException e) {
			throw new IllegalArgumentException(
					"Invalid geo " + min + "," + max, e);
		}
		BooleanQuery result = new BooleanQuery(true);
		DocField subField;
		FieldType subFieldType;
		for (int i = 0; i < dimension; i++) {
			subField = getSubField(field, i);
			subFieldType = subField.getFieldType();
			result.add(subFieldType.getRangeQuery(parser, subField, p1[i],
					p2[i], minInclusive, maxInclusive),
					BooleanClause.Occur.MUST);
		}
		return result;
	}

	@Override
	public Query getFieldQuery(QueryParser parser, DocField field, String value) {
		String[] p1;
		int dimension = getDimension();
		try {
			p1 = DistanceUtils.parsePoint(null, value, dimension);
		} catch (InvalidGeoException e) {
			throw new IllegalArgumentException("Invalid geo " + value, e);
		}
		BooleanQuery result = new BooleanQuery(true);
		DocField subField;
		Query subQuery;
		FieldType subFieldType;
		for (int i = 0; i < dimension; i++) {
			subField = getSubField(field, i);
			subFieldType = subField.getFieldType();
			subQuery = subFieldType.getFieldQuery(parser, subField, p1[i]);
			result.add(subQuery, BooleanClause.Occur.MUST);
		}
		return result;
	}

	protected DocField getSubField(DocField field, int i) {
		return null;
	}

}
